package gqz.testdemo.Bluetooth;

import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;

import gqz.testdemo.R;

/**
 * Created by Administrator on 2018/9/1.
 */

public class BleServer extends Activity {

    private String TAG = "BleGATTServer-->";
    //先定几个服务类型的UUID
     /* 当前时间服务UUID */
    public static UUID TIME_SERVICE = UUID.fromString("00001805-0000-1000-8000-00805f9b34fb");
    /* 强制当前时间信息特征UUID */
    public static UUID CURRENT_TIME = UUID.fromString("00002a2b-0000-1000-8000-00805f9b34fb");
    /* 可选的本地时间信息特征 */
    public static UUID LOCAL_TIME_INFO = UUID.fromString("00002a0f-0000-1000-8000-00805f9b34fb");
    /* 强制客户端特征配置描述符UUID */
    public static UUID CLIENT_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");

    boolean bleEnable = false;

    private BluetoothManager bm;
    private BluetoothAdapter ba;
    private BluetoothGatt gatt;
    private BluetoothGattServer gattServer;
    private BluetoothLeAdvertiser leAdvertiser;

    Switch switch_ble, switch_search;
    TextView tv_name, tv_content;
    ProgressBar pb;

    private ArrayList<BluetoothDevice> connDevs = new ArrayList<>();//请求数据的设备

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bleserver);
        openAndInitBt();
    }

    private void initView() {
        switch_ble = findViewById(R.id.ble_switch_ble);
        switch_search = findViewById(R.id.ble_switch_AllowSearch);
        pb = findViewById(R.id.ble_pb);
        tv_name = findViewById(R.id.ble_tv_name);
        tv_content = findViewById(R.id.ble_tv_content);
        tv_name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showRenameDialog();
            }
        });

        switch_ble.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setBleOpenStatus();
            }
        });
        switch_search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                Log.i(TAG, "onClick: check status:"+switch_search.isChecked());
                if (switch_search.isChecked()) {
                    openAllowSearch(300);
                } else {
                    closeAllowSearch();
                }
            }
        });
    }

    //显示重命名弹窗
    public void showRenameDialog() {
        AlertDialog.Builder b = new AlertDialog.Builder(this);
        b.setTitle("修改本机名称");
        final EditText et = new EditText(this);
        et.setText(tv_name.getText().toString());
        b.setView(et);
        b.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        b.setPositiveButton("修改", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ba.setName(et.getText().toString());
                dialog.dismiss();
                getBleName();
            }
        });
        b.create().show();
    }

    //获取本机蓝牙名称
    public void getBleName() {
        tv_name.setText(ba.getName());
    }

    //设置蓝牙开关
    public void setBleOpenStatus() {
        if (bleEnable)
            ba.disable();
        else
            ba.enable();
        switch_ble.setEnabled(false);
    }

    //开启允许检测
    public void openAllowSearch(int timeout) {
        try {
            Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
            setDiscoverableTimeout.setAccessible(true);
            Method setScanMode = BluetoothAdapter.class.getMethod("setScanMode", int.class, int.class);
            setScanMode.setAccessible(true);

            setDiscoverableTimeout.invoke(ba, timeout);
            setScanMode.invoke(ba, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeout);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //关闭允许检测
    public void closeAllowSearch() {
        try {
            Method setDiscoverableTimeout = BluetoothAdapter.class.getMethod("setDiscoverableTimeout", int.class);
            setDiscoverableTimeout.setAccessible(true);
            Method setScanMode = BluetoothAdapter.class.getMethod("setScanMode", int.class, int.class);
            setScanMode.setAccessible(true);

            setDiscoverableTimeout.invoke(ba, 1);
            setScanMode.invoke(ba, BluetoothAdapter.SCAN_MODE_CONNECTABLE, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //1.初始化并打开蓝牙
    private void openAndInitBt() {
        bm = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        ba = bm.getAdapter();
        if (ba == null) {
            return;
        }//不支持蓝牙
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            return;//不支持ble蓝牙
        }
        //.判断蓝牙是否打开
        if (!ba.enable()) {
            //没打开请求打开
            Intent btEnable = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(btEnable, 100);
        }
    }

    //2.创建GATT服务
    private void createGattServer() {
        //2.1.新建一个服务
        BluetoothGattService gattService = new BluetoothGattService(TIME_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY);
        //2.2 新建一个Characteristic
        BluetoothGattCharacteristic curTimeCha = new BluetoothGattCharacteristic(CURRENT_TIME,
                //只读的特征, 支持通知
                BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY,
                BluetoothGattCharacteristic.PERMISSION_READ);
        //2.3 新建特性描述并配置--这一步非必需
        BluetoothGattDescriptor configDescriptor = new BluetoothGattDescriptor(CLIENT_CONFIG,
                //Read/write descriptor
                BluetoothGattDescriptor.PERMISSION_READ | BluetoothGattDescriptor.PERMISSION_WRITE);
        curTimeCha.addDescriptor(configDescriptor);//将描述符添加到特征
        //2.4 将特征配置到服务
        gattService.addCharacteristic(curTimeCha);
        //2.5 打开外围设备  注意这个services和server的区别
        gattServer = bm.openGattServer(this, gattServerCallback);
        if (gattServer == null) {
            return;
        }
        gattServer.addService(gattService);
    }

    /**
     * 回调以处理对GATT服务器的传入请求
     * 所有characteristics 和 descriptors 的读写请求都在这里处理
     */
    private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
        @Override
        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
            super.onConnectionStateChange(device, status, newState);
            Log.i(TAG, "onConnectionStateChange: ");
            //连接状态改变
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                Log.i(TAG, "BluetoothDevice CONNECTED: " + device);
                connDevs.add(device);
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                Log.i(TAG, "BluetoothDevice DISCONNECTED: " + device);
                connDevs.remove(device);
            }
        }

        @Override
        public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
            Log.i(TAG, "onCharacteristicReadRequest: ");
            //请求读特征 如果包含有多个服务，就要区分请求读的是什么，这里我只有一个服务
            if (CURRENT_TIME.equals(characteristic.getUuid())) {
                //回应
                gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, "请求读特征的回应".getBytes());
            }
        }

        //这个实际可以用于反向写数据
        @Override
        public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic,
                                                 boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
            super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
            Log.i(TAG, "onCharacteristicWriteRequest: ");
        }

        @Override
        public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
            super.onDescriptorReadRequest(device, requestId, offset, descriptor);
            Log.i(TAG, "onDescriptorReadRequest: ");
            if (CLIENT_CONFIG.equals(descriptor.getUuid())) {
                Log.d(TAG, "Config descriptor read");
                byte[] returnValue;
                if (connDevs.contains(device)) {
                    returnValue = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
                } else {
                    returnValue = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
                }
                gattServer.sendResponse(device,
                        requestId,
                        BluetoothGatt.GATT_SUCCESS,
                        0,
                        returnValue);
            } else {
                Log.w(TAG, "Unknown descriptor read request");
                gattServer.sendResponse(device,
                        requestId,
                        BluetoothGatt.GATT_FAILURE,
                        0,
                        null);
            }
        }

        @Override
        public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite,
                                             boolean responseNeeded, int offset, byte[] value) {
            super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);
            Log.i(TAG, "onDescriptorWriteRequest: ");
            if (CLIENT_CONFIG.equals(descriptor.getUuid())) {
                if (Arrays.equals(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE, value)) {
                    Log.d("", "Subscribe device to notifications: " + device);
                    connDevs.add(device);
                } else if (Arrays.equals(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE, value)) {
                    Log.d("", "Unsubscribe device from notifications: " + device);
                    connDevs.remove(device);
                }

                if (responseNeeded) {
                    gattServer.sendResponse(device,
                            requestId,
                            BluetoothGatt.GATT_SUCCESS,
                            0,
                            null);
                }
            } else {
                Log.w("", "Unknown descriptor write request");
                if (responseNeeded) {
                    gattServer.sendResponse(device,
                            requestId,
                            BluetoothGatt.GATT_FAILURE,
                            0,
                            null);
                }
            }
        }

        @Override
        public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
            super.onExecuteWrite(device, requestId, execute);
            Log.i(TAG, "onExecuteWrite: ");
        }

        @Override
        public void onNotificationSent(BluetoothDevice device, int status) {
            super.onNotificationSent(device, status);
            Log.i(TAG, "onNotificationSent: ");
        }
    };

    //3.通知服务开启
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void startAdvertising() {
        leAdvertiser = ba.getBluetoothLeAdvertiser();
        if (leAdvertiser == null) {
            //创建失败
            return;
        }
        AdvertiseSettings settings = new AdvertiseSettings.Builder()
                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)//广告模式，有高性能（高功耗），平衡，低功耗（低性能）
                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)//指定使用那种TX功率级别进行广告。这对应于广告包的最大可见范围。
                .setConnectable(true)
                .setTimeout(0)//广告时限。不得超过180000毫秒。值为0将禁用时间限制。
                .build();

        AdvertiseData data = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)//设置设备名称是否应包含在Advertise包中
                .setIncludeTxPowerLevel(false)//传输功率电平是否应包含在广告包中
                .addServiceUuid(new ParcelUuid(TIME_SERVICE))//绑定服务uuid
                .build();
        leAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
    }

    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            Log.i(TAG, "LE Advertise Started.");
        }

        @Override
        public void onStartFailure(int errorCode) {
            Log.w(TAG, "LE Advertise Failed: " + errorCode);
        }
    };

    //4.模拟数据更新
    private void updateCharacteristic() {
        if (gattServer == null) {
            return;
        }
        final Handler updateHandler = new Handler();
        updateHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                for (BluetoothDevice d : connDevs) {
                    BluetoothGattCharacteristic newCharacteristic = gattServer
                            .getService(TIME_SERVICE)
                            .getCharacteristic(CURRENT_TIME);
                    byte[] data = ("数据更新" + System.currentTimeMillis()).getBytes();
                    newCharacteristic.setValue(data);
                    gattServer.notifyCharacteristicChanged(d, newCharacteristic, false);
                }
                updateHandler.postDelayed(this, 5000);

            }
        }, 5000);//5s更新一次
        outputLog("数据模拟更新启动");
    }

    private void outputLog(String txt) {
        tv_content.append(txt + "\n");
    }

    @Override
    protected void onDestroy() {
        if (leAdvertiser != null) {
            leAdvertiser.stopAdvertising(mAdvertiseCallback);
        }
        if (gattServer != null) {
            gattServer.close();
        }
        super.onDestroy();
    }
}
